#!/bin/bash

set -e

USAGE="USAGE: $(basename "$0") [run|edit|dockerfile] <docker_params>"
GOSS_FILES_PATH="${GOSS_FILES_PATH:-.}"

info() {
    echo -e "INFO: $*" >&2;
}
error() {
    echo -e "ERROR: $*" >&2;
    exit 1;
}

cleanup() {
    set +e
    { kill "$log_pid" && wait "$log_pid"; } 2> /dev/null
    rm -rf "$tmp_dir"
    if [[ $id ]];then
        info "Deleting container"
        docker rm -vf "$id" > /dev/null
    fi
}

# Copy goss & any config into a folder which then gets mounted as a volume
# Run the container and perform the checks
setup_container(){
    info "Setting up test dir"
    cp "${GOSS_PATH}" "$tmp_dir/goss"
    chmod 755 "$tmp_dir/goss"
    [[ -e "${GOSS_FILES_PATH}/goss.yaml" ]] && cp "${GOSS_FILES_PATH}/goss.yaml" "$tmp_dir"
    [[ -e "${GOSS_FILES_PATH}/goss_wait.yaml" ]] && cp "${GOSS_FILES_PATH}/goss_wait.yaml" "$tmp_dir"
    [[ ! -z "${GOSS_VARS}" ]] && [[ -e "${GOSS_FILES_PATH}/${GOSS_VARS}" ]] && cp "${GOSS_FILES_PATH}/${GOSS_VARS}" "$tmp_dir"
    # copy the Dockerfile if path has been provided
    [[ ! -z "${3}" ]] && [[ "${3}" == *"Dockerfile"* ]] && cp "${3}" "$tmp_dir"
    info "Setup complete"

    # Switch between mount or cp files strategy
    GOSS_FILES_STRATEGY=${GOSS_FILES_STRATEGY:="mount"}
    case "$GOSS_FILES_STRATEGY" in
      mount)
        info "Starting docker container"
        id=$(docker run -d -v "$tmp_dir:/goss:z" "${@:2}")
        docker logs -f "$id" > "$tmp_dir/docker_output.log" 2>&1 &
        ;;
      cp)
        info "Creating docker container"
        id=$(docker create ${@:2})
        info "Copy goss files into container"
        docker cp $tmp_dir/. $id:/goss
        info "Starting docker container"
        docker start $id > /dev/null
        ;;
      *) error "Wrong goss files strategy used! Correct options are \"mount\" or \"cp\"."
    esac

    log_pid=$!
    info "Container ID: ${id:0:8}"
}

get_file_from_docker() {
    if docker exec "$id" sh -c "test -e $1" > /dev/null;then
        mkdir -p "${GOSS_FILES_PATH}"
        info "Copied '$1' from container to '${GOSS_FILES_PATH}'"
        docker cp "$id:$1" "${GOSS_FILES_PATH}"
    fi
}

# Main
tmp_dir=$(mktemp -d /tmp/tmp.XXXXXXXXXX)
chmod 777 "$tmp_dir"
trap 'ret=$?;cleanup;exit $ret' EXIT

GOSS_PATH="${GOSS_PATH:-$(which goss 2> /dev/null || true)}"
[[ $GOSS_PATH ]] || { error "Couldn't find goss installation, please set GOSS_PATH to it"; }
[[ ${GOSS_OPTS+x} ]] || GOSS_OPTS="--color --format documentation"
[[ ${GOSS_WAIT_OPTS+x} ]] || GOSS_WAIT_OPTS="-r 30s -s 1s > /dev/null"
GOSS_SLEEP=${GOSS_SLEEP:-0.2}

case "$1" in
    run)
        info "Run Docker tests"
        setup_container "$@"
        if [[ -e "${GOSS_FILES_PATH}/goss_wait.yaml" ]]; then
            info "Found goss_wait.yaml, waiting for it to pass before running tests"
            if [[ -z "${GOSS_VARS}" ]]; then
                if ! docker exec "$id" sh -c "/goss/goss -g /goss/goss_wait.yaml validate $GOSS_WAIT_OPTS"; then
                    error "goss_wait.yaml never passed"
                fi
            else
                if ! docker exec "$id" sh -c "/goss/goss -g /goss/goss_wait.yaml --vars='/goss/${GOSS_VARS}' validate $GOSS_WAIT_OPTS"; then
                    error "goss_wait.yaml never passed"
                fi
            fi
        fi
        [[ $GOSS_SLEEP ]] && { info "Sleeping for $GOSS_SLEEP"; sleep "$GOSS_SLEEP"; }
        # info "Container health"
        # if ! docker top $id; then
        #     docker logs $id
        # fi
        info "Running Tests"
        if [[ -z "${GOSS_VARS}" ]]; then
            docker exec "$id" sh -c "/goss/goss -g /goss/goss.yaml validate $GOSS_OPTS"
        else
            docker exec "$id" sh -c "/goss/goss -g /goss/goss.yaml --vars='/goss/${GOSS_VARS}' validate $GOSS_OPTS"
        fi
        ;;
    dockerfile)
        info "Run Dockerfile tests"
        setup_container "$@"
        docker exec "$id" sh -c "cat /goss/goss.yaml"
        docker exec "$id" sh -c "/goss/goss -g /goss/goss.yaml validate $GOSS_OPTS"
        ;;
    edit)
        setup_container "$@"
        info "Run goss add/autoadd to add resources"
        docker exec -it "$id" sh -c 'cd /goss; PATH="/goss:$PATH" exec sh'
        get_file_from_docker "/goss/goss.yaml"
        get_file_from_docker "/goss/goss_wait.yaml"
        [[ ! -z "${GOSS_VARS}" ]] && get_file_from_docker "/goss/${GOSS_VARS}"
        ;;
    *)
        error "$USAGE"
esac
